package alit.generator.web.servlet;

import alit.generator.bl.generator.DataGenerator;
import alit.generator.bl.populator.*;
import alit.generator.web.exception.GeneratorCallException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * User: Alexander Litvinenko
 * Date: 11/27/11
 * Time: 4:06 PM
 */
public class GeneratorCallServlet extends HttpServlet {

    private static final Logger LOGGER = Logger.getLogger(GeneratorCallServlet.class.getName());
    public static final String PARAM_SOURCE = "paramSource";
    public static final String PARAM_SEPARATOR = "paramSeparator";
    public static final String PARAM_RANDOM = "paramRandom";
    public static final String PARAM_WRAP = "paramWrap";

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/plain");
        try {
            DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            Document document = builder.parse(new ByteArrayInputStream(request.getParameter("xml").getBytes()));
            document.toString();
            String tableName = document.getFirstChild().getAttributes().getNamedItem("name").getNodeValue();
            if (tableName == null) {
                throw new GeneratorCallException("There is no table name!");
            }
            DataGenerator generator = new DataGenerator();
            generator.setTableName(tableName);
            Node rowCount = document.getFirstChild().getAttributes().getNamedItem("rowcount");
            if (rowCount != null) {
                generator.setRowCount(Integer.parseInt(rowCount.getNodeValue()));
            }
            NodeList columns = document.getElementsByTagName("column");
            for (int i = 0; i < columns.getLength(); i++) {
                Element element = (Element) columns.item(i);
                String name = element.getAttribute("name");
                Element populatorElement = (Element) element.getFirstChild();
                String populatorId = populatorElement.getAttribute("id");
                if (populatorId == null) {
                    throw new GeneratorCallException("populator id is null!");
                }
                String type = element.getAttribute("type");
                if (type.equals(BitPopulatorKit.TYPE)) {
                    chooseFromBitPopulatorKit(generator, populatorElement, populatorId, name);
                } else if (type.equals(IntPopulatorKit.TYPE)) {
                    chooseFromIntPopulatorKit(generator, populatorElement, populatorId, name);
                } else if (type.equals(FloatPopulatorKit.TYPE)) {
                    chooseFromFloatPopulatorKit(generator, populatorElement, populatorId, name);
                } else if (type.equals(DatetimePopulatorKit.TYPE)) {
                    chooseFromDatetimePopulatorKit(generator, populatorElement, populatorId, name);
                } else if (type.equals(VarcharPopulatorKit.TYPE)) {
                    chooseFromVarcharPopulatorKit(generator, populatorElement, populatorId, name);
                }
            }
            response.getWriter().print(generator.generate());
        } catch (Exception e) {
            response.getWriter().print(e.getMessage());
            LOGGER.log(Level.SEVERE, "Exception caught!", e);
        }
    }

    private boolean chooseFromPopulatorKit(DataGenerator generator, Element populatorElement,
                                           String populatorId, String name) throws GeneratorCallException {
        if (populatorId.equals(PopulatorKit.NullPopulator.getId())) {
            generator.registerColumn(name, new BitPopulatorKit.NullPopulator());
            return true;
        }
        if (populatorId.equals(PopulatorKit.FromSourcePopulator.getId())) {
            String source;
            String separator;
            boolean random;
            String wrap;
            NodeList params = populatorElement.getElementsByTagName("parameter");
            if (params.getLength() != 4) {
                throw new GeneratorCallException("Expected 4 parameters. But got " + params.getLength());
            }
            Map<String, String> id2value = new HashMap<String, String>();
            for (int i = 0; i < params.getLength(); i++) {
                id2value.put(((Element) params.item(i)).getAttribute("id"), params.item(i).getTextContent());
            }
            if (id2value.containsKey(PARAM_SOURCE)) {
                source = id2value.get(PARAM_SOURCE);
            } else {
                throw new GeneratorCallException(PARAM_SOURCE + " is not found.");
            }
            if (id2value.containsKey(PARAM_SEPARATOR)) {
                separator = id2value.get(PARAM_SEPARATOR);
            } else {
                throw new GeneratorCallException(PARAM_SEPARATOR + " is not found.");
            }
            if (id2value.containsKey(PARAM_RANDOM)) {
                random = Boolean.parseBoolean(id2value.get(PARAM_RANDOM));
            } else {
                throw new GeneratorCallException(PARAM_RANDOM + " is not found.");
            }
            if (id2value.containsKey(PARAM_WRAP)) {
                wrap = id2value.get(PARAM_WRAP);
            } else {
                throw new GeneratorCallException(PARAM_WRAP + " is not found.");
            }

            generator.registerColumn(name, new BitPopulatorKit.FromSourcePopulator(source, separator, random, wrap));
            return true;
        }
        return false;
    }

    private void chooseFromBitPopulatorKit(DataGenerator generator, Element populatorElement,
                                           String populatorId, String name) throws GeneratorCallException {
        if (chooseFromPopulatorKit(generator, populatorElement, populatorId, name)) return;
        if (populatorId.equals(BitPopulatorKit.FromAllRangePopulator.getId())) {
            generator.registerColumn(name, new BitPopulatorKit.FromAllRangePopulator());
        }
    }

    private void chooseFromIntPopulatorKit(DataGenerator generator, Element populatorElement,
                                           String populatorId, String name) throws GeneratorCallException {
        if (chooseFromPopulatorKit(generator, populatorElement, populatorId, name)) return;
        if (populatorId.equals(IntPopulatorKit.FromAllRangePopulator.getId())) {
            generator.registerColumn(name, new IntPopulatorKit.FromAllRangePopulator());
        }
    }

    private void chooseFromFloatPopulatorKit(DataGenerator generator, Element populatorElement,
                                             String populatorId, String name) throws GeneratorCallException {
        if (chooseFromPopulatorKit(generator, populatorElement, populatorId, name)) return;
        if (populatorId.equals(FloatPopulatorKit.FromAllRangePopulator.getId())) {
            generator.registerColumn(name, new FloatPopulatorKit.FromAllRangePopulator());
        }
    }

    private void chooseFromDatetimePopulatorKit(DataGenerator generator, Element populatorElement,
                                                String populatorId, String name) throws GeneratorCallException {
        if (chooseFromPopulatorKit(generator, populatorElement, populatorId, name)) return;
        if (populatorId.equals(DatetimePopulatorKit.FromAllRangePopulator.getId())) {
            generator.registerColumn(name, new DatetimePopulatorKit.FromAllRangePopulator());
        }
    }

    private void chooseFromVarcharPopulatorKit(DataGenerator generator, Element populatorElement,
                                               String populatorId, String name) throws GeneratorCallException {
        if (chooseFromPopulatorKit(generator, populatorElement, populatorId, name)) return;
        if (populatorId.equals(VarcharPopulatorKit.FromAllRangePopulator.getId())) {
            generator.registerColumn(name, new VarcharPopulatorKit.FromAllRangePopulator());
        } else if (populatorId.equals(VarcharPopulatorKit.CalculatedFieldPopulator.getId())) {
            String expression = "";
            NodeList params = populatorElement.getElementsByTagName("parameter");
            if (params.getLength() != 1) {
                throw new GeneratorCallException("Expected 1 parameter. But got " + params.getLength());
            }
            String paramId = ((Element) params.item(0)).getAttribute("id");
            if (paramId.equals("paramExpression")) {
                expression = params.item(0).getTextContent();
            } else {
                throw new GeneratorCallException("Expected paramExpression. But got " + paramId);
            }
            generator.registerColumn(name, new VarcharPopulatorKit.CalculatedFieldPopulator(expression));
        }
    }
}